package basic;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class BasicJava {

    /**
     * 基本数据类型
     * byte/8
     * char/16
     * short/16
     * int/16
     * float/32
     * long/64
     * double/64
     * boolean/1 (JVM编译boolean转化为int，1表示true,0表示false)
     *
     * 包装类型
     * 装箱Integer.valueOf()
     * 拆箱x.intValue()
     *
     * 缓冲池
     * new Integer(0) 新建一个对象
     * Integer.valueOf() 查看缓冲池中有没有该对象，多次调用会取得同一个对象的引用。
     * （在 jdk 1.8 所有的数值类缓冲池中，Integer 的缓冲池 IntegerCache 很特殊，这个缓冲池的下界是 - 128，上界默认是 127，但是这个上界是可调的，在启动 jvm 的时候，通过 -XX:AutoBoxCacheMax=<size> 来指定这个缓冲池的大小，该选项在 JVM 初始化的时候会设定一个名为 java.lang.IntegerCache.high 系统属性，然后 IntegerCache 初始化的时候就会读取该系统属性来决定上界。）
     *
     * String
     * String被声明为final,不能被继承 （java8 string内部用char数组存储数据，java9 用byte存储 coder标识编码 设施final保证string不可变）
     *
     * 不可变的好处
     * 1、String的hash值不会变，只需要进行一次计算
     * 2、string pool中要求string对象不变，外部调用引用
     * 3、作为参数保证了安全性
     * 4、线程安全
     *
     * StringBuffer and StringBuilder
     * StringBuffer和StringBuilder可变，StringBuffer线程安全（synchronized） StringBuilder线程不安全
     *
     * String pool
     * String的intern()方法在运行过程将字符串添加到String Pool中。在Java 7之前，String Pool被放在运行时常量池中，它属于永久代。而在 Java 7，String Pool 被移到堆中。这是因为永久代的空间有限，在大量使用字符串的场景下会导致 OutOfMemoryError 错误。
     *
     * new String("abc")
     * 使用这种方式一共会创建两个字符串对象（前提是 String Pool 中还没有 "abc" 字符串对象）。
     * "abc" 属于字符串字面量，因此编译时期会在 String Pool 中创建一个字符串对象，指向这个 "abc" 字符串字面量；
     * 而使用 new 的方式会在堆中创建一个字符串对象。
     *
     * 运算
     * 参数传递
     * Java的参数是以值传递的形式传入方法中，而不是引用传递
     * float 与 double
     *
     * 隐式类型转换
     * 使用 += 或者 ++ 运算符会执行隐式类型转换
     *
     * switch
     * 从 Java 7 开始，可以在 switch 条件判断语句中使用 String 对象，switch 不支持 long
     *
     * 关键字
     * final
     * 1、data:声明数据为常量，可以是编译时常量，也可以是在运行时被初始化后不能被改变的常量。对于基本类型，final 使数值不变；对于引用类型，final 使引用不变，也就不能引用其它对象，但是被引用的对象本身是可以修改的。
     * 2、function:声明方法不能被子类重写。private 方法隐式地被指定为 final，如果在子类中定义的方法和基类中的一个 private 方法签名相同，此时子类的方法不是重写基类方法，而是在子类中定义了一个新的方法。
     * 3、class:声明类不允许被继承。
     *
     * static
     * 静态变量
     * 静态变量：又称为类变量，也就是说这个变量属于类的，类所有的实例都共享静态变量，可以直接通过类名来访问它。静态变量在内存中只存在一份。
     * 实例变量：每创建一个实例就会产生一个实例变量，它与该实例同生共死。
     * 静态方法
     * 静态方法在类加载的时候就存在了，它不依赖于任何实例。所以静态方法必须有实现，也就是说它不能是抽象方法。只能访问所属类的静态字段和静态方法，方法中不能有 this 和 super 关键字，因此这两个关键字与具体对象关联。
     * 静态语句块
     * 静态语句块在类初始化时运行一次。
     * 静态内部类
     * 非静态内部类依赖于外部类的实例，也就是说需要先创建外部类实例，才能用这个实例去创建非静态内部类。而静态内部类不需要。静态内部类不能访问外部类的非静态的变量和方法。
     * 静态导包
     * 在使用静态变量和方法时不用再指明 ClassName，从而简化代码，但可读性大大降低。
     * 初始化顺序
     * 静态变量和静态语句块优先于实例变量和普通语句块，静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。
     * 存在继承的情况下，初始化顺序为：
     * 父类（静态变量、静态语句块）
     * 子类（静态变量、静态语句块）
     * 父类（实例变量、普通语句块）
     * 父类（构造函数）
     * 子类（实例变量、普通语句块）
     * 子类（构造函数）
     *
     * Object 通用方法
     * equals()
     * 对于基本类型，== 判断两个值是否相等，基本类型没有 equals() 方法。
     * 对于引用类型，== 判断两个变量是否引用同一个对象，而 equals() 判断引用的对象是否等价。
     * 检查是否为同一个对象的引用，如果是直接返回 true；
     * 检查是否是同一个类型，如果不是，直接返回 false；
     * 将 Object 对象进行转型；
     * 判断每个关键域是否相等。
     * hashCode()
     * hashCode() 返回哈希值，而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同，但是散列值相同的两个对象不一定等价，这是因为计算哈希值具有随机性，两个值不同的对象可能计算出相同的哈希值。
     * 在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法，保证等价的两个对象哈希值也相等。
     * HashSet 和 HashMap 等集合类使用了 hashCode() 方法来计算对象应该存储的位置，因此要将对象添加到这些集合类中，需要让对应的类实现 hashCode() 方法。
     * toString()
     * 默认返回 ToStringExample@4554617c 这种形式，其中 @ 后面的数值为散列码的无符号十六进制表示。
     * clone()
     * clone() 是 Object 的 protected 方法，它不是 public，一个类不显式去重写 clone()，其它类就不能直接去调用该类实例的 clone() 方法。
     * 浅拷贝:拷贝对象和原始对象的引用类型引用同一个对象。
     * 深拷贝:拷贝对象和原始对象的引用类型引用不同对象。
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     * @param args
     */
    public static void main(String[] args) {
//        String path = "D:\\";
//        String nameFilePath = path + "name.txt";
//        String copyFilePath = path + "copy.txt";
//        File nf = new File(nameFilePath);
//        File cf = new File(copyFilePath);
//        try(FileChannel inChannel = new FileInputStream(nf).getChannel();
//            FileChannel outChannel = new FileOutputStream(cf).getChannel()){
//            MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY,0,nf.length());
//            outChannel.write(buffer);
//            buffer.clear();
//            Charset charset = Charset.forName("GBK");
//            CharsetDecoder decoder = charset.newDecoder();
//            CharBuffer charBuffer = decoder.decode(buffer);
//            System.out.println(charBuffer);
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        DemoServer server = new DemoServer();
        server.start();
        try(Socket client = new Socket(InetAddress.getLocalHost(),server.getPort())){
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
            bufferedReader.lines().forEach(s-> System.out.println(s));
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class DemoServer extends Thread{

    private ServerSocket serverSocket;

    public int getPort(){
        return serverSocket.getLocalPort();
    }

    @Override
    public void run() {
        try{
            serverSocket = new ServerSocket(0);
            while (true){
                Socket socket = serverSocket.accept();
                RequestHandler requestHandler = new RequestHandler(socket);
                requestHandler.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(serverSocket != null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class RequestHandler extends Thread{

    private Socket socket;

    RequestHandler(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        try (PrintWriter out = new PrintWriter(socket.getOutputStream())) {
            out.println("Hello world!");
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}